package com.me.libgdx_test;

import java.io.File;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;

import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Stage;


public class ClassRefinedAssetHolder {
	private ClassLogDisplay logger;
	private String path = "";
	private Point game_dimensions,screen_size,bottom_left,format_offset;
	private ClassStringArray[][] board;
	private ClassSpriteStack[][] map;
	private ClassSpriteStack hud;
	private ClassDungeonPlaceElement dungeon_vars;
	private ClassHudObject hud_holder;
	private ClassTexturePackerLoader sprite_holder;
	//private ClassAnimationTextureLoader animation_textures;
	private ClassSpriteObjectPool pool, hud_pool;
	private boolean animation_residue;
	//we need to save this here so that the camera can focus on the sprite
	private int multiplier;
	
	private Sprite holder;
	public ClassRefinedAssetHolder(Point game_dimensions, Point screen_size, ClassReferenceDrawable game_vars, 
			ClassTexturePackerLoader sprite_holder, Stage stage, ClassSkinReference skin){
		logger = new ClassLogDisplay("ClassRefinedAssetHolder");
		
		logger.print(path);
		dungeon_vars = new ClassDungeonPlaceElement(game_dimensions,path, game_vars, sprite_holder.get_animations(), screen_size, stage, skin);
		hud = new ClassSpriteStack();
		pool = new ClassSpriteObjectPool(game_dimensions);
		hud_pool = new ClassSpriteObjectPool(new Point(6,6));
		
		this.game_dimensions = game_dimensions;
		board = dungeon_vars.return_board();
		this.screen_size = screen_size;
		bottom_left = new Point( -(screen_size.x/2),-(screen_size.y/2-1));
		multiplier = this.screen_size.x/this.game_dimensions.x;
		//Without this, the board will be buried under the hud
		format_offset = new Point(150,180);
		hud_holder = new ClassHudObject(path, screen_size, dungeon_vars.get_animations(), dungeon_vars.get_text_animations(), sprite_holder.get_animations());
		this.sprite_holder = sprite_holder;
		//this.animation_textures = animation_textures;
		generate_sprite_region();
		generate_hud();
	}
	
	public ClassDungeonPlaceElement get_dungeon_vars(){
		return dungeon_vars;
	} 
	
	public boolean has_current_animations(){
		return dungeon_vars.has_current_animations() || animation_residue;
	}
	
	public void generate_hud(){
		//ClassCharacterEnemy enemy = dungeon_vars.is_enemy_there(dungeon_vars.get_current_cursor());
		hud_holder.refresh_hud(dungeon_vars.get_player_object(), 
				dungeon_vars.is_something_there(dungeon_vars.get_current_cursor()), 
				dungeon_vars.get_place_objects());
		add_hud_to_pool();
	}
	
	public void add_hud_to_pool(){
		//hud.get_stack().clear();
		hud_pool.free_list();
		logger.print("Start hud pool");
		for (ClassHudFit hud_object: hud_holder.get_hud_objects()){
			
			logger.print(hud_object.image);
			hud_pool.add_sprite(sprite_holder.find_by_name(hud_object.image), hud_object.bottom_left, hud_object.dimensions,false);
			
			//holder = new Sprite(manager.get(hud_object.image, Texture.class));
			/*holder = new Sprite(sprite_holder.find_by_name(hud_object.image));
			holder.setBounds(hud_object.bottom_left.x,hud_object.bottom_left.y,
					hud_object.dimensions.x,hud_object.dimensions.y);
			hud.add_stack(holder);*/
		}
		animation_residue = false;
		
		//The animations MUST be at the end of the spritepool otherwise sprites will be overwritten...
		for(ClassAnimationIterator animation: dungeon_vars.get_animations()){
			if(animation.animation_moving()){
				Sprite frame = sprite_holder.find_by_name(animation.get_frame());
				hud_pool.add_sprite(frame, 
						animation.get_intermediate_point(), new Point((int)frame.getWidth()*animation.get_animation_size(),
								(int)frame.getHeight()*animation.get_animation_size()),true);
				if(animation.animation_over()){
					dungeon_vars.get_animations().remove(animation);
					animation_residue = true;
				}
			}
		}
		logger.print("Hud pool size: " + hud_pool.get_pool().length);
		hud_pool.print_pool();
	}
	
	public ClassCharacterPlayer get_player_object(){
		return dungeon_vars.get_player_object();
	}
	
	public Point get_player_refined_location(){
		Point refined_location = new Point(dungeon_vars.get_player_object().location);
		refined_location.move(3*bottom_left.x/4 + refined_location.x * multiplier, bottom_left.y/2 + refined_location.y * multiplier);
		return refined_location;
	}
	
	//This converts the board coordinates into camera coordinates
	public Point to_projection(float board_x, float board_y){
		float new_x = format_offset.x + bottom_left.x + board_x * multiplier;
		float new_y = format_offset.y + bottom_left.y + board_y * multiplier;
		return new Point((int)new_x,(int)new_y);
	}
	
	//Finds the sprites from the refinedassetholder class to sent to the game activity
	public void generate_sprite_region(){
		pool.free_list();
		for (int y = 0; y < game_dimensions.y; y++){
			for (int x = 0; x < game_dimensions.x; x++){
				//int new_x = bottom_left.x + x * multiplier;
				//int new_y = bottom_left.y + y * multiplier;
				for(String string: board[x][y].string_holder){
					
					//logger.print("Passed Sprite: " + string);
					
					if(string.contains("number_")){
						pool.add_sprite(sprite_holder.find_by_name(string), 
								to_projection(x,y), 
								new Point(multiplier/2, multiplier/2), false);
					}else if(string.contains("animation")){
						pool.add_sprite(sprite_holder.find_by_name(string), 
								to_projection(x,y), 
								new Point(multiplier, multiplier), true);
					}else{
						pool.add_sprite(sprite_holder.find_by_name(string), 
								to_projection(x,y), 
								new Point(multiplier, multiplier), false);
					}
				}
			}
		}
		for(ClassAnimationString animation: dungeon_vars.get_text_animations()){
			if(!animation.location_converted()){
				animation.convert_location(to_projection(animation.get_location().x+.5f,animation.get_location().y+.5f));
			}
		}
	}
	
	public void reset_animations(){
		add_hud_to_pool();
		
		for (int y = 0; y < game_dimensions.y; y++){
			for (int x = 0; x < game_dimensions.x; x++){
				for(String string: board[x][y].string_holder){
					if(string.contains("animation")){
						board[x][y].string_holder.remove(string);
					}
				}
			}
		}
		for(ClassAnimationIterator animation : dungeon_vars.get_animations()){
			if(!animation.animation_moving()){
				board[animation.get_location().x][animation.get_location().y].string_holder.add(animation.get_frame());
				//This is why animation must be a CopyOnWriteArrayList
				if(animation.animation_over()){
					dungeon_vars.get_animations().remove(animation);
					animation_residue = true;
				}
			}
		}
		
		generate_sprite_region();
	}
	
	public void refresh_board(){
		reset_animations();
		
		/*dungeon_vars.create_board();
		board = dungeon_vars.return_board();
		
		generate_sprite_region();
		generate_hud();*/
	}
	
	public void push_touch(Touch touch){
		//convert touch to x/y coordinates here
		touch.print_click();
		ClickConvert click = new ClickConvert(touch.get_last_touch(),touch.get_untranslated_last_touch());
		logger.print("Original Click");
		logger.print(click.get_point());
		if(click.get_valid()){
			logger.print("Click");
			logger.print(click.get_point());
			if(click.get_hud_click()){
				//This needs to be first bc the click action may set overlays
				//that will be overwritten when generate_hud is called
				if(hud_holder.check_hud_click(click.get_point(),path)){
					//Need to check for shop purchase
					logger.print("Refresh sprites");
					//Need to add the animations before the board is refreshed
					pull_player_animations();
					dungeon_vars.create_board();
					board = dungeon_vars.return_board();
					generate_sprite_region();
				}else{
					hud_holder.reset_spell_selector();
				}
				generate_hud();
			}else{
				logger.print(String.valueOf(click.new_point.x) + "-" + String.valueOf(click.new_point.y));
				logger.print("Off Hud Click Actions Start");
				dungeon_vars.push_touch(click.get_point());
				
				//Need to add the animations before the board is refreshed
				pull_player_animations();
				
				dungeon_vars.get_player_object().check_for_death();
				board = dungeon_vars.return_board();
				hud_holder.reset_spell_selector();
				hud_holder.reset_details();
				generate_sprite_region();
				generate_hud();
				logger.print("Off Hud Click Actions End");
			}
		}else{
			logger.print("Click not valid");
			logger.print(click.get_point());
		}
	}
	
	public int get_bosses(){
		int bosses = 0;
		for(ClassCharacterEnemy enemy:dungeon_vars.get_place_objects().get_enemies()){
			if(enemy.level==10){
				bosses++;
			}
		}
		return bosses;
	}
	
	public void pull_player_animations(){
		for(String animation : dungeon_vars.get_player_object().get_player_animations()){
			logger.print("Player Animation: " + animation);
			for(int y = dungeon_vars.get_player_object().get_location().y-1;y<dungeon_vars.get_player_object().get_location().y+2;y++){
				for(int x = dungeon_vars.get_player_object().get_location().x-1;x<dungeon_vars.get_player_object().get_location().x+2;x++){
					if(y >-1 && x > -1 && y < game_dimensions.y && x < game_dimensions.x){
						dungeon_vars.get_animations().add(new ClassAnimationIterator(new Point(x,y),
								sprite_holder.get_animations().return_animation_by_name(animation),3,1));
					}
				}
			}
		}
		dungeon_vars.get_player_object().get_player_animations().clear();
	}
	
	public ClassHudObject get_hud_object(){
		return hud_holder;
	}
	
	public ClassSpriteStack return_sprite_hud(){
		return hud;
	}
	
	public ClassSpriteStack[][] return_sprite_region(){
		return map;
	}
	
	public ClassSpriteObjectPool return_sprite_pool(){
		return pool;
	}
	
	public ClassSpriteObjectPool return_hud_pool(){
		return hud_pool;
	}
	
	public boolean just_moved(){
		return dungeon_vars.just_moved();
	}
	
	public CopyOnWriteArrayList<ClassAnimationString> get_text_animations(){
		return dungeon_vars.get_text_animations();
	}
	
	private class ClickConvert{
		private Point new_point;
		private boolean valid = true;
		private boolean hud_click = false;
		ClickConvert(Point p,Point untranslated_p){
			/*
			 * If untranslated_p
			 */
			
			
			
			new_point = new Point();
			/*logger.print("maxX: " + (format_offset.x+bottom_left.x+(game_dimensions.x)*multiplier) + " currentX: " + p.x);
			logger.print("maxY: " + (format_offset.y+bottom_left.y+(game_dimensions.y)*multiplier) + " currentY: " + p.y);
			if (format_offset.x+bottom_left.x+(game_dimensions.x)*multiplier < p.x || format_offset.y+bottom_left.y+(game_dimensions.y)*multiplier < p.y ||
					bottom_left.x+format_offset.x > p.x || bottom_left.y+format_offset.y > p.y){
				valid = false;
			}else{*/
				logger.print("Untranslated: " + String.valueOf(untranslated_p.y));
				logger.print("Bounds");
				ClassLogDisplay.print(screen_size.y - hud_holder.get_hud_dimensions().y);
				if(untranslated_p.y<screen_size.y - hud_holder.get_hud_dimensions().y){
					for (int x = 0; x < game_dimensions.x+1; x++){
						//logger.print("point: " + p.x + " multiplier: " + (format_offset.x +bottom_left.x+x*multiplier));
						if (format_offset.x + bottom_left.x+x*multiplier > p.x){
							new_point.x = x-1;
							if(new_point.x<0){
								valid = false;
							}
							break;
						}
					}
					for (int y = 0; y < game_dimensions.y+1; y++){
						//logger.print("point: " + p.y + " multiplier: " + (format_offset.y +bottom_left.y + y*multiplier));
						if (format_offset.y + bottom_left.y + y*multiplier > p.y){
							new_point.y = y-1;
							if(new_point.y<0){
								valid = false;
							}
							break;
						}
					}
				}else{
					hud_click = true;
					new_point = new Point(untranslated_p.x,screen_size.y - untranslated_p.y);
				}
			//}
		}
		public boolean get_valid(){
			return valid;
		}
		public Point get_point(){
			return new_point;
		}
		public boolean get_hud_click(){
			return hud_click;
		}
	}
}
